﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace UtilZ.Dotnet.Ex.Base
{
    /// <summary>
    /// Enumerable扩展类
    /// </summary>
    unsafe public partial class EnumerableEx
    {
        #region 泛型类型

        /// <summary>
        /// 查找double数组中最大值与最大值首次出现的索引
        /// </summary>
        /// <param name="items">数据集合</param>
        /// <param name="startIndex">起始位置</param>
        /// <param name="count">查找的数据个数</param>
        /// <param name="selector">数据获取器</param>
        /// <returns>结果</returns>
        public static MaxMinValueIndexInfo<TResult> FindMaxIndex<TSource, TResult>(IEnumerable<TSource> items, int startIndex, int count, Func<TSource, TResult> selector)
            where TResult : struct, IComparable<TResult>
        {
            if (count < 1)
            {
                return new MaxMinValueIndexInfo<TResult>(null, null, null, null);
            }

            int end = startIndex + count;
            int maxValueIndex = startIndex;
            TResult maxValue = selector(items.ElementAt(startIndex));
            TResult tmp;

            for (int i = startIndex + 1; i < end; i++)
            {
                tmp = selector(items.ElementAt(i));
                if (tmp.CompareTo(maxValue) > 0)
                {
                    maxValue = tmp;
                    maxValueIndex = i;
                }
            }

            return new MaxMinValueIndexInfo<TResult>(null, null, maxValue, maxValueIndex);
        }

        /// <summary>
        /// 查找double指针中最小值与最小值首次出现的索引
        /// </summary>
        /// <param name="items">数据集合</param>
        /// <param name="startIndex">起始位置</param>
        /// <param name="count">查找的数据个数</param>
        /// <param name="selector">数据获取器</param>
        /// <returns>结果</returns>
        public static MaxMinValueIndexInfo<TResult> FindMinIndex<TSource, TResult>(IEnumerable<TSource> items, int startIndex, int count, Func<TSource, TResult> selector)
            where TResult : struct, IComparable<TResult>
        {
            if (count < 1)
            {
                return new MaxMinValueIndexInfo<TResult>(null, null, null, null);
            }

            int end = startIndex + count;
            int minValueIndex = startIndex;
            TResult minValue = selector(items.ElementAt(startIndex));
            TResult tmp;

            for (int i = startIndex + 1; i < end; i++)
            {
                tmp = selector(items.ElementAt(i));

                if (tmp.CompareTo(minValue) < 0)
                {
                    minValue = tmp;
                    minValueIndex = i;
                }
            }

            return new MaxMinValueIndexInfo<TResult>(minValue, minValueIndex, null, null);
        }

        /// <summary>
        /// 查找double指针中最大最小值与最大最小值首次出现的索引
        /// </summary>
        /// <param name="items">数据集合</param>
        /// <param name="startIndex">起始位置</param>
        /// <param name="count">查找的数据个数</param>
        /// <param name="selector">数据获取器</param>
        /// <returns>结果</returns>
        public static MaxMinValueIndexInfo<TResult> FindMinMaxIndex<TSource, TResult>(IEnumerable<TSource> items, int startIndex, int count, Func<TSource, TResult> selector)
            where TResult : struct, IComparable<TResult>
        {
            if (count < 1)
            {
                return new MaxMinValueIndexInfo<TResult>(null, null, null, null);
            }

            int end = startIndex + count;
            int minValueIndex = startIndex;
            TResult minValue = selector(items.ElementAt(startIndex));
            int maxValueIndex = startIndex;
            TResult maxValue = selector(items.ElementAt(startIndex));
            TResult tmp;

            for (int i = startIndex + 1; i < end; i++)
            {
                tmp = selector(items.ElementAt(i));

                if (tmp.CompareTo(minValue) < 0)
                {
                    minValue = tmp;
                    minValueIndex = i;
                }

                if (tmp.CompareTo(minValue) > 0)
                {
                    maxValue = tmp;
                    maxValueIndex = i;
                }
            }

            return new MaxMinValueIndexInfo<TResult>(minValue, minValueIndex, maxValue, maxValueIndex);
        }

        #endregion

    }



    /// <summary>
    /// 最大最小值及其索引信息结构
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public struct MaxMinValueIndexInfo<T> where T : struct
    {
        /// <summary>
        /// 最小值
        /// </summary>
        public readonly T? MinValue;

        /// <summary>
        /// 最小值索引
        /// </summary>
        public readonly int? MinValueIndex;

        /// <summary>
        /// 最大值
        /// </summary>
        public readonly T? MaxValue;

        /// <summary>
        /// 最大值索引
        /// </summary>
        public readonly int? MaxValueIndex;


        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="minValue">最小值</param>
        /// <param name="minValueIndex">最小值索引</param>
        /// <param name="maxValue">最大值</param>
        /// <param name="maxValueIndex">最大值索引</param>
        public MaxMinValueIndexInfo(T? minValue, int? minValueIndex, T? maxValue, int? maxValueIndex)
        {
            this.MinValue = minValue;
            this.MinValueIndex = minValueIndex;
            this.MaxValue = maxValue;
            this.MaxValueIndex = maxValueIndex;
        }



        /// <summary>
        /// 重写ToString
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            if (this.MinValue.HasValue)
            {
                if (this.MaxValue.HasValue)
                {
                    return $"MinValue:{MinValue},MinValueIndex:{MinValueIndex}  MaxValue:{MaxValue},MaxValueIndex:{MaxValueIndex}";
                }
                else
                {
                    return $"MinValue:{MinValue},MinValueIndex:{MinValueIndex}";
                }
            }
            else
            {
                if (this.MaxValue.HasValue)
                {
                    return $"MaxValue:{MaxValue},MaxValueIndex:{MaxValueIndex}";
                }
                else
                {
                    return base.ToString();
                }
            }

        }

    }
}
